home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / iv / Dispatch / dispatcher.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  18KB  |  774 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989, 1990, 1991 Stanford University
  3.  * Copyright (c) 1991 Silicon Graphics, Inc.
  4.  *
  5.  * Permission to use, copy, modify, distribute, and sell this software and 
  6.  * its documentation for any purpose is hereby granted without fee, provided
  7.  * that (i) the above copyright notices and this permission notice appear in
  8.  * all copies of the software and related documentation, and (ii) the names of
  9.  * Stanford and Silicon Graphics may not be used in any advertising or
  10.  * publicity relating to the software without the specific, prior written
  11.  * permission of Stanford and Silicon Graphics.
  12.  * 
  13.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  14.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  15.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  16.  *
  17.  * IN NO EVENT SHALL STANFORD OR SILICON GRAPHICS BE LIABLE FOR
  18.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  19.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  20.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  21.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  22.  * OF THIS SOFTWARE.
  23.  */
  24.  
  25. // Dispatcher provides an interface to the "select" system call.
  26.  
  27. #include <Dispatch/dispatcher.h>
  28. #include <Dispatch/iohandler.h>
  29. #include <OS/memory.h>
  30. #include <OS/types.h>
  31. #include <errno.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35. #undef NULL
  36. #include <sys/param.h>
  37. #if defined(AIXV3) || defined(svr4)
  38. #include <sys/select.h>
  39. #endif
  40. #include <sys/time.h>
  41. #include <time.h>
  42. #include <sys/wait.h>
  43. #include <signal.h>
  44. #include <limits.h>
  45.  
  46. #include "port.h"
  47.  
  48. Dispatcher* Dispatcher::_instance;
  49.  
  50. class FdMask : public fd_set {
  51. public:
  52.     FdMask();
  53.     void zero();
  54.     void setBit(int);
  55.     void clrBit(int);
  56.     boolean isSet(int) const;
  57.     boolean anySet() const;
  58.     int numSet() const;
  59. };
  60.  
  61. FdMask::FdMask() {
  62.     zero();
  63. }
  64.  
  65. void FdMask::zero() { Memory::zero(this, sizeof(FdMask)); }
  66. void FdMask::setBit(int fd) { FD_SET(fd,this); }
  67. void FdMask::clrBit(int fd) { FD_CLR(fd,this); }
  68. boolean FdMask::isSet(int fd) const { return FD_ISSET(fd,this); }
  69.  
  70. boolean FdMask::anySet() const {
  71.     const int mskcnt = howmany(FD_SETSIZE,NFDBITS);
  72.     for (int i = 0; i < mskcnt; i++) {
  73.     if (fds_bits[i]) {
  74.         return true;
  75.     }
  76.     }
  77.     return false;
  78. }
  79.  
  80. int FdMask::numSet() const {
  81.     const int mskcnt = howmany(FD_SETSIZE,NFDBITS);
  82.     int n = 0;
  83.     for (int i = 0; i < mskcnt; i++) {
  84.     if (fds_bits[i]) {
  85.         for (int j = 0; j < NFDBITS; j++) {
  86.         if ((fds_bits[i] & (1 << j)) != 0) {
  87.             n += 1;
  88.         }
  89.         }
  90.     }
  91.     }
  92.     return n;
  93. }
  94.  
  95. /*
  96.  * Operations on timeval structures.
  97.  */
  98.  
  99. const long ONE_SECOND = 1000000;
  100.  
  101. timeval operator+(timeval src1, timeval src2) {
  102.     timeval sum;
  103.     sum.tv_sec = src1.tv_sec + src2.tv_sec;
  104.     sum.tv_usec = src1.tv_usec + src2.tv_usec;
  105.     if (sum.tv_usec >= ONE_SECOND) {
  106.     sum.tv_usec -= ONE_SECOND;
  107.     sum.tv_sec++;
  108.     } else if (sum.tv_sec >= 1 && sum.tv_usec < 0) {
  109.     sum.tv_usec += ONE_SECOND;
  110.     sum.tv_sec--;
  111.     }
  112.     return sum;
  113. }
  114.  
  115. timeval operator-(timeval src1, timeval src2) {
  116.     timeval delta;
  117.     delta.tv_sec = src1.tv_sec - src2.tv_sec;
  118.     delta.tv_usec = src1.tv_usec - src2.tv_usec;
  119.     if (delta.tv_usec < 0) {
  120.     delta.tv_usec += ONE_SECOND;
  121.     delta.tv_sec--;
  122.     } else if (delta.tv_usec >= ONE_SECOND) {
  123.     delta.tv_usec -= ONE_SECOND;
  124.     delta.tv_sec++;
  125.     }
  126.     return delta;
  127. }
  128.  
  129. boolean operator>(timeval src1, timeval src2) {
  130.     if (src1.tv_sec > src2.tv_sec) {
  131.     return true;
  132.     } else if (src1.tv_sec == src2.tv_sec && src1.tv_usec > src2.tv_usec) {
  133.     return true;
  134.     } else {
  135.     return false;
  136.     }
  137. }
  138.  
  139. boolean operator<(timeval src1, timeval src2) {
  140.     if (src1.tv_sec < src2.tv_sec) {
  141.     return true;
  142.     } else if (src1.tv_sec == src2.tv_sec && src1.tv_usec < src2.tv_usec) {
  143.     return true;
  144.     } else {
  145.     return false;
  146.     }
  147. }
  148.  
  149. /*
  150.  * Interface to timers.
  151.  */
  152.  
  153. struct Timer {
  154.     Timer(timeval t, IOHandler* h, Timer* n);
  155.  
  156.     timeval timerValue;
  157.     IOHandler* handler;
  158.     Timer* next;
  159. };
  160.  
  161. class TimerQueue {
  162. public:
  163.     TimerQueue();
  164.     virtual ~TimerQueue();
  165.  
  166.     boolean isEmpty() const;
  167.     static timeval zeroTime();
  168.     timeval earliestTime() const;
  169.     static timeval currentTime();
  170.  
  171.     void insert(timeval, IOHandler*);
  172.     void remove(IOHandler*);
  173.     void expire(timeval);
  174. private:
  175.     Timer* _first;
  176.     static timeval _zeroTime;
  177. };
  178.  
  179. Timer::Timer(timeval t, IOHandler* h, Timer* n) :
  180.     timerValue(t),
  181.     handler(h),
  182.     next(n) {}
  183.  
  184. timeval TimerQueue::_zeroTime;
  185.  
  186. TimerQueue::TimerQueue() :
  187.     _first(nil) {}
  188.  
  189. TimerQueue::~TimerQueue() {
  190.     Timer* doomed = _first;
  191.     while (doomed != nil) {
  192.     Timer* next = doomed->next;
  193.     delete doomed;
  194.     doomed = next;
  195.     }
  196. }
  197.  
  198. inline boolean TimerQueue::isEmpty() const {
  199.     return _first == nil;
  200. }
  201.  
  202. inline timeval TimerQueue::zeroTime() {
  203.     return _zeroTime;
  204. }
  205.  
  206. inline timeval TimerQueue::earliestTime() const {
  207.     return _first->timerValue;
  208. }
  209.  
  210. timeval TimerQueue::currentTime() {
  211.     timeval curTime;
  212. #if defined(svr4) && !defined(__GNUC__)
  213.     gettimeofday(&curTime, 0);
  214. #else
  215.     struct timezone curZone;
  216.     gettimeofday(&curTime, &curZone);
  217. #endif
  218.     return curTime;
  219. }
  220.  
  221. void TimerQueue::insert(timeval futureTime, IOHandler* handler) {
  222.     if (isEmpty() || futureTime < earliestTime()) {
  223.     _first = new Timer(futureTime, handler, _first);
  224.     } else {
  225.     Timer* before = _first;
  226.     Timer* after = _first->next;
  227.     while (after != nil && futureTime > after->timerValue) {
  228.         before = after;
  229.         after = after->next;
  230.     }
  231.     before->next = new Timer(futureTime, handler, after);
  232.     }
  233. }
  234.  
  235. void TimerQueue::remove(IOHandler* handler) {
  236.     Timer* before = nil;
  237.     Timer* doomed = _first;
  238.     while (doomed != nil && doomed->handler != handler) {
  239.     before = doomed;
  240.     doomed = doomed->next;
  241.     }
  242.     if (doomed != nil) {
  243.     if (before == nil) {
  244.         _first = doomed->next;
  245.     } else {
  246.         before->next = doomed->next;
  247.     }
  248.     delete doomed;
  249.     }
  250. }
  251.  
  252. void TimerQueue::expire(timeval curTime) {
  253.     while (!isEmpty() && earliestTime() < curTime) {
  254.     Timer* expired = _first;
  255.     _first = _first->next;
  256.     expired->handler->timerExpired(curTime.tv_sec, curTime.tv_usec);
  257.     delete expired;
  258.     }
  259. }
  260.  
  261. /*
  262.  * Interface to child process handling.
  263.  */
  264.  
  265. struct Child {
  266.     Child(pid_t pid, IOHandler* h, Child* n);
  267.  
  268.     pid_t    pid;        // process's PID
  269.     int        status;        // wait status
  270.     IOHandler*    handler;    // associated handler
  271.     Child*    next;
  272. };
  273.  
  274. class ChildQueue {
  275. public:
  276.     ChildQueue();
  277.     virtual ~ChildQueue();
  278.  
  279.     boolean isEmpty() const;
  280.     boolean isReady() const;
  281.  
  282.     void insert(pid_t, IOHandler*);
  283.     void remove(IOHandler*);
  284.     void notify();
  285.     void setStatus(pid_t, int status);
  286. private:
  287.     Child* _first;        // queue head
  288.     boolean _ready;        // something is ready
  289. };
  290.  
  291. Child::Child(pid_t p, IOHandler* h, Child* n)
  292. {
  293.     pid = p;
  294.     status = -1;
  295.     handler = h;
  296.     next = n;
  297. }
  298.  
  299. ChildQueue::ChildQueue()
  300. {
  301.     _first = nil;
  302.     _ready = false;
  303. }
  304.  
  305. ChildQueue::~ChildQueue() {
  306.     Child* doomed = _first;
  307.     while (doomed != nil) {
  308.     Child* next = doomed->next;
  309.     delete doomed;
  310.     doomed = next;
  311.     }
  312. }
  313.  
  314. inline boolean ChildQueue::isEmpty() const { return _first == nil; }
  315. inline boolean ChildQueue::isReady() const { return _ready; }
  316.  
  317. void ChildQueue::insert(pid_t p, IOHandler* handler) {
  318.     if (isEmpty()) {
  319.     _first = new Child(p, handler, _first);
  320.     } else {
  321.     Child* before = _first;
  322.     Child* after = _first->next;
  323.     while (after != nil && p > after->pid) {
  324.         before = after;
  325.         after = after->next;
  326.     }
  327.     before->next = new Child(p, handler, after);
  328.     }
  329. }
  330.  
  331. void ChildQueue::remove(IOHandler* handler) {
  332.     Child* before = nil;
  333.     Child* doomed = _first;
  334.     while (doomed != nil && doomed->handler != handler) {
  335.     before = doomed;
  336.     doomed = doomed->next;
  337.     }
  338.     if (doomed != nil) {
  339.     if (before == nil) {
  340.         _first = doomed->next;
  341.     } else {
  342.         before->next = doomed->next;
  343.     }
  344.     delete doomed;
  345.     }
  346. }
  347.  
  348. void ChildQueue::setStatus(pid_t p, int status) {
  349.     for (Child* c = _first; c != nil; c = c->next)
  350.     if (c->pid == p) {
  351.         c->status = status;
  352.         _ready = true;
  353.         break;
  354.     }
  355. }
  356.  
  357. void ChildQueue::notify() {
  358.     Child** prev = &_first;
  359.     Child* c;
  360.  
  361.     while ((c = *prev) != nil) {
  362.     if (c->status != -1) {
  363.         c->handler->childStatus(c->pid, c->status);
  364.         *prev = c->next;
  365.         delete c;
  366.     } else
  367.         prev = &c->next;
  368.     }
  369.     _ready = false;
  370. }
  371.  
  372. Dispatcher::Dispatcher() {
  373.     _nfds = 0;
  374.     _rmask = new FdMask;
  375.     _wmask = new FdMask;
  376.     _emask = new FdMask;
  377.     _rmaskready = new FdMask;
  378.     _wmaskready = new FdMask;
  379.     _emaskready = new FdMask;
  380.     _rtable = new IOHandler*[_POSIX_OPEN_MAX];
  381.     _wtable = new IOHandler*[_POSIX_OPEN_MAX];
  382.     _etable = new IOHandler*[_POSIX_OPEN_MAX];
  383.     _queue = new TimerQueue;
  384.     _cqueue = new ChildQueue;
  385.     for (int i = 0; i < _POSIX_OPEN_MAX; i++) {
  386.     _rtable[i] = nil;
  387.     _wtable[i] = nil;
  388.     _etable[i] = nil;
  389.     }
  390. }
  391.  
  392. Dispatcher::~Dispatcher() {
  393.     delete _rmask;
  394.     delete _wmask;
  395.     delete _emask;
  396.     delete _rmaskready;
  397.     delete _wmaskready;
  398.     delete _emaskready;
  399.     delete _rtable;
  400.     delete _wtable;
  401.     delete _etable;
  402.     delete _queue;
  403.     delete _cqueue;
  404. }
  405.  
  406. Dispatcher& Dispatcher::instance() {
  407.     if (_instance == nil) {
  408.     _instance = new Dispatcher;
  409.     }
  410.     return *_instance;
  411. }
  412.  
  413. void Dispatcher::instance(Dispatcher* d) { _instance = d; }
  414.  
  415. IOHandler* Dispatcher::handler(int fd, DispatcherMask mask) const {
  416.     if (fd < 0 || fd >= _POSIX_OPEN_MAX) {
  417.     abort();
  418.     }
  419.     IOHandler* cur = nil;
  420.     if (mask == ReadMask) {
  421.     cur = _rtable[fd];
  422.     } else if (mask == WriteMask) {
  423.     cur = _wtable[fd];
  424.     } else if (mask == ExceptMask) {
  425.     cur = _etable[fd];
  426.     } else {
  427.     abort();
  428.     }
  429.     return cur;
  430. }
  431.  
  432. void Dispatcher::link(int fd, DispatcherMask mask, IOHandler* handler) {
  433.     if (fd < 0 || fd >= _POSIX_OPEN_MAX) {
  434.     abort();
  435.     }
  436.     attach(fd, mask, handler);
  437. }
  438.  
  439. void Dispatcher::unlink(int fd) {
  440.     if (fd < 0 || fd >= _POSIX_OPEN_MAX) {
  441.     abort();
  442.     }
  443.     detach(fd);
  444. }
  445.  
  446. void Dispatcher::attach(int fd, DispatcherMask mask, IOHandler* handler) {
  447.     if (mask == ReadMask) {
  448.     _rmask->setBit(fd);
  449.     _rtable[fd] = handler;
  450.     } else if (mask == WriteMask) {
  451.     _wmask->setBit(fd);
  452.     _wtable[fd] = handler;
  453.     } else if (mask == ExceptMask) {
  454.     _emask->setBit(fd);
  455.     _etable[fd] = handler;
  456.     } else {
  457.     abort();
  458.     }
  459.     if (_nfds < fd+1) {
  460.     _nfds = fd+1;
  461.     }
  462. }
  463.  
  464. void Dispatcher::detach(int fd) {
  465.     _rmask->clrBit(fd);
  466.     _rtable[fd] = nil;
  467.     _wmask->clrBit(fd);
  468.     _wtable[fd] = nil;
  469.     _emask->clrBit(fd);
  470.     _etable[fd] = nil;
  471.     if (_nfds == fd+1) {
  472.     while (_nfds > 0 && _rtable[_nfds-1] == nil &&
  473.            _wtable[_nfds-1] == nil && _etable[_nfds-1] == nil
  474.     ) {
  475.         _nfds--;
  476.     }
  477.     }
  478. }
  479.  
  480. void Dispatcher::startTimer(long sec, long usec, IOHandler* handler) {
  481.     timeval deltaTime;
  482.     deltaTime.tv_sec = sec;
  483.     deltaTime.tv_usec = usec;
  484.     _queue->insert(TimerQueue::currentTime() + deltaTime, handler);
  485. }
  486.  
  487. void Dispatcher::stopTimer(IOHandler* handler) {
  488.     _queue->remove(handler);
  489. }
  490.  
  491. void Dispatcher::startChild(pid_t pid, IOHandler* handler) {
  492.     _cqueue->insert(pid, handler);
  493. }
  494.  
  495. void Dispatcher::stopChild(IOHandler* handler) {
  496.     _cqueue->remove(handler);
  497. }
  498.  
  499. boolean Dispatcher::setReady(int fd, DispatcherMask mask) {
  500.     if (handler(fd, mask) == nil) {
  501.     return false;
  502.     }
  503.     if (mask == ReadMask) {
  504.     _rmaskready->setBit(fd);
  505.     } else if (mask == WriteMask) {
  506.     _wmaskready->setBit(fd);
  507.     } else if (mask == ExceptMask) {
  508.     _emaskready->setBit(fd);
  509.     } else {
  510.     return false;
  511.     }
  512.     return true;
  513. }
  514.  
  515. void Dispatcher::dispatch() {
  516.     dispatch(nil);
  517. }
  518.  
  519. boolean Dispatcher::dispatch(long& sec, long& usec) {
  520.     timeval howlong;
  521.     timeval prevTime;
  522.     timeval elapsedTime;
  523.  
  524.     howlong.tv_sec = sec;
  525.     howlong.tv_usec = usec;
  526.     prevTime = TimerQueue::currentTime();
  527.  
  528.     boolean success = dispatch(&howlong);
  529.  
  530.     elapsedTime = TimerQueue::currentTime() - prevTime;
  531.     if (howlong > elapsedTime) {
  532.     howlong = howlong - elapsedTime;
  533.     } else {
  534.     howlong = TimerQueue::zeroTime(); /* Used all of timeout */
  535.     }
  536.  
  537.     sec = howlong.tv_sec;
  538.     usec = howlong.tv_usec;
  539.     return success;
  540. }
  541.  
  542. boolean Dispatcher::dispatch(timeval* howlong) {
  543.     FdMask rmaskret;
  544.     FdMask wmaskret;
  545.     FdMask emaskret;
  546.     int nfound;
  547.  
  548.     if (anyReady()) {
  549.     nfound = fillInReady(rmaskret, wmaskret, emaskret);
  550.     } else {
  551.     nfound = waitFor(rmaskret, wmaskret, emaskret, howlong);
  552.     }
  553.  
  554.     notify(nfound, rmaskret, wmaskret, emaskret);
  555.  
  556.     return (nfound != 0);
  557. }
  558.  
  559. boolean Dispatcher::anyReady() const {
  560.     return
  561.        _rmaskready->anySet() || _wmaskready->anySet() || _emaskready->anySet();
  562. }
  563.  
  564. int Dispatcher::fillInReady(
  565.     FdMask& rmaskret, FdMask& wmaskret, FdMask& emaskret
  566. ) {
  567.     rmaskret = *_rmaskready;
  568.     wmaskret = *_wmaskready;
  569.     emaskret = *_emaskready;
  570.     _rmaskready->zero();
  571.     _wmaskready->zero();
  572.     _emaskready->zero();
  573.     return rmaskret.numSet() + wmaskret.numSet() + emaskret.numSet();
  574. }
  575.  
  576. void Dispatcher::sigCLD(int)
  577. {
  578.     pid_t pid;
  579.     int status;
  580.  
  581. #ifdef ibmrt
  582.     while ((pid = wait(&status)) > 0)
  583. #else
  584.     while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
  585. #endif
  586.     Dispatcher::instance()._cqueue->setStatus(pid, status);
  587. }
  588.  
  589. #ifndef fxSIGHANDLER
  590. #define    fxSIGHANDLER
  591. #endif
  592. #ifndef fxSIGVECHANDLER
  593. #define    fxSIGVECHANDLER
  594. #endif
  595. #ifndef fxSIGACTIONHANDLER
  596. #define    fxSIGACTIONHANDLER
  597. #endif
  598.  
  599. #ifndef SA_INTERRUPT
  600. #define    SA_INTERRUPT    0
  601. #endif
  602.  
  603. int Dispatcher::waitFor(
  604.     FdMask& rmaskret, FdMask& wmaskret, FdMask& emaskret, timeval* howlong
  605. ) {
  606.     int nfound;
  607. #ifdef SV_INTERRUPT            /* BSD-style */
  608.     static struct sigvec sv, osv;
  609. #else
  610. #ifdef SA_NOCLDSTOP            /* POSIX */
  611.     static struct sigaction sa, osa;
  612. #else                    /* System V-style */
  613.     void (*osig)();
  614. #endif
  615. #endif
  616.  
  617.     if (!_cqueue->isEmpty()) {
  618. #ifdef SV_INTERRUPT            /* BSD-style */
  619.     sv.sv_handler = fxSIGVECHANDLER(&Dispatcher::sigCLD);
  620.     sv.sv_flags = SV_INTERRUPT;
  621.     sigvec(SIGCHLD, &sv, &osv);
  622. #else
  623. #ifdef SA_NOCLDSTOP            /* POSIX */
  624.     sa.sa_handler = fxSIGACTIONHANDLER(&Dispatcher::sigCLD);
  625.     sa.sa_flags = SA_INTERRUPT;
  626.     sigaction(SIGCLD, &sa, &osa);
  627. #else                    /* System V-style */
  628.     osig = (void (*)())signal(SIGCLD, fxSIGHANDLER(&Dispatcher::sigCLD));
  629. #endif
  630. #endif
  631.     }
  632.     do {
  633.     rmaskret = *_rmask;
  634.     wmaskret = *_wmask;
  635.     emaskret = *_emask;
  636.     howlong = calculateTimeout(howlong);
  637.  
  638. #if defined(hpux)
  639.       nfound = select(
  640.           _nfds, (int*)&rmaskret, (int*)&wmaskret, (int*)&emaskret, howlong
  641.       );
  642. #else
  643.      nfound = select(_nfds, &rmaskret, &wmaskret, &emaskret, howlong);
  644. #endif
  645. #ifdef SGISELECTBUG
  646.         // XXX hack to deal with IRIX 5.2 FIFO+select bug
  647.         if (wmaskret.anySet()) {
  648.         for (int i = 0; i < _nfds; i++)
  649.         if (wmaskret.isSet(i) && !_wmask->isSet(i)) {
  650. printf("select incorrectly returns bit %d set in write mask\n", i);
  651.             wmaskret.clrBit(i);
  652.         }
  653.         }
  654.         if (emaskret.anySet()) {
  655.         for (int i = 0; i < _nfds; i++)
  656.         if (emaskret.isSet(i) && !_emask->isSet(i)) {
  657. printf("select incorrectly returns bit %d set in exception mask\n", i);
  658.             emaskret.clrBit(i);
  659.         }
  660.         }
  661. #endif
  662.     } while (nfound < 0 && !handleError());
  663.     if (!_cqueue->isEmpty()) {
  664. #ifdef SV_INTERRUPT            /* BSD-style */
  665.     sigvec(SIGCHLD, &osv, (struct sigvec*) 0);
  666. #else
  667. #ifdef SA_NOCLDSTOP            /* POSIX */
  668.     sigaction(SIGCLD, &osa, (struct sigaction*) 0);
  669. #else                    /* System V-style */
  670.     (void) signal(SIGCLD, fxSIGHANDLER(osig));
  671. #endif
  672. #endif
  673.     }
  674.  
  675.     return nfound;        /* Timed out or input available */
  676. }
  677.  
  678. void Dispatcher::notify(
  679.     int nfound, FdMask& rmaskret, FdMask& wmaskret, FdMask& emaskret
  680. ) {
  681.     for (int i = 0; i < _nfds && nfound > 0; i++) {
  682.     if (rmaskret.isSet(i)) {
  683.         int status = _rtable[i]->inputReady(i);
  684.         if (status < 0) {
  685.         detach(i);
  686.         } else if (status > 0) {
  687.         _rmaskready->setBit(i);
  688.         }
  689.         nfound--;
  690.     }
  691.     if (wmaskret.isSet(i)) {
  692.         int status = _wtable[i]->outputReady(i);
  693.         if (status < 0) {
  694.         detach(i);
  695.         } else if (status > 0) {
  696.         _wmaskready->setBit(i);
  697.         }
  698.         nfound--;
  699.     }
  700.     if (emaskret.isSet(i)) {
  701.         int status = _etable[i]->exceptionRaised(i);
  702.         if (status < 0) {
  703.         detach(i);
  704.         } else if (status > 0) {
  705.         _emaskready->setBit(i);
  706.         }
  707.         nfound--;
  708.     }
  709.     }
  710.  
  711.     if (!_queue->isEmpty()) {
  712.     _queue->expire(TimerQueue::currentTime());
  713.     }
  714.     if (_cqueue->isReady()) {
  715.     _cqueue->notify();
  716.     }
  717. }
  718.  
  719. timeval* Dispatcher::calculateTimeout(timeval* howlong) const {
  720.     static timeval timeout;
  721.  
  722.     if (!_queue->isEmpty()) {
  723.     timeval curTime;
  724.  
  725.     curTime = TimerQueue::currentTime();
  726.     if (_queue->earliestTime() > curTime) {
  727.         timeout = _queue->earliestTime() - curTime;
  728.         if (howlong == nil || *howlong > timeout) {
  729.         howlong = &timeout;
  730.         }
  731.     } else {
  732.         timeout = TimerQueue::zeroTime();
  733.         howlong = &timeout;
  734.     }
  735.     }
  736.     return howlong;
  737. }
  738.  
  739. boolean Dispatcher::handleError() {
  740.     switch (errno) {
  741.     case EBADF:
  742.     checkConnections();
  743.     break;
  744.     case EINTR:
  745.     if (_cqueue->isReady())
  746.         return true;
  747.     break;
  748.     default:
  749.     perror("Dispatcher: select");
  750.     exit(1);
  751.     /*NOTREACHED*/
  752.     }
  753.     return false;            // retry select
  754. }
  755.  
  756. void Dispatcher::checkConnections() {
  757.     FdMask rmask;
  758.     timeval poll = TimerQueue::zeroTime();
  759.  
  760.     for (int fd = 0; fd < _nfds; fd++) {
  761.     if (_rtable[fd] != nil) {
  762.         rmask.setBit(fd);
  763. #if defined(hpux)
  764.           if (select(fd+1, (int*)&rmask, nil, nil, &poll) < 0) {
  765. #else
  766.         if (select(fd+1, &rmask, nil, nil, &poll) < 0) {
  767. #endif
  768.         detach(fd);
  769.         }
  770.         rmask.clrBit(fd);
  771.     }
  772.     }
  773. }
  774.